from flask import session

from . import passport_bp
from flask import request,jsonify, abort, current_app, make_response
from info.utlis.captcha.captcha import captcha
from info import constants, redis_store, db

import json
from info.utlis.response_code import RET
import re
from info.models import User
from info.lib.yuntongxun.sms import CCP
import random
from datetime import datetime


@passport_bp.route('/login_out',methods=["POST"])
def login_out():
    """退出登陆接口"""
    # 清除session保存的用户信息
    session.pop("user_id")
    session.pop("mobile")
    session.pop("nick_name")
    # 退出登录的时候 需要清除管理员数据， 防止普通用户进入
    session.pop("is_admin", None)

    return jsonify(errno=RET.OK, errmsg="退出登陆成功")



@passport_bp.route('/login', methods=["POST"])
def login():
    """登陆接口"""
    """
    1.获取参数
        1.1 手机号码（未加密）
    2.校验参数
        2.1 非空判断
        2.2 手机号码格式
    3.逻辑处理
        3.1 根据手机号码查询用户对象
        3.2 对比用户填写的密码和用户对象中的密码是否一致
        3.3 一致：记录最后一次登陆时间 使用session记录用户登陆信息
    4.返回值处理
    """
    # 1.1 手机号码 用户填写的短信验证码 密码（未加密）
    params_dict = request.json
    mobile = params_dict.get("mobile")
    password = params_dict.get("password")

    # 2.1 非空判断
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")
    # 2.2手机号码格式判断
    if not re.match('^1[356789][0-9]{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机格式错误")

    #  3.1 根据手机号码查询用户对象
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")

    #     3.2 对比用户填写的密码和用户对象中的密码是否一致
    if not user.check_passowrd(password):
        return jsonify(errno=RET.DATAERR, errmsg="密码填写错误")

    #     3.3 一致：记录最后一次登陆时间 使用session记录用户登陆信息
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session["nick_name"] = user.nick_name

    # 修改最后一次登陆时间
    user.last_login = datetime.now()

    # 当修改了模型身上的属性的时候 （不需要add）
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="用户对象保存到数据库异常")
    # 4.返回响应对象
    return jsonify(errno=RET.OK, errmsg="登陆成功")



# /possport/register POST请求方法
@passport_bp.route('/register', methods=["POST"])
def register():
    """用户注册接口"""
    """
    1. 获取参数
        1.1 手机号码 用户填写的短信验证码 密码（未加密）
    2.校验参数
        2.1 非空判断
        2.2 手机号码格式判断
    3.逻辑处理
        3.1 根据手机号码拼接SMS_1335685273这个key去redis获取真实短信验证码
        3.2 对比用户添加的短信验证码和真实的短信验证码对比
        3.3 一致：根据User模型创建用户对象，保存到数据库
        3.4 一般而言：用户注册成功的话，第一次到会给用户自动登陆
    4.返回值处理
    """
    # 1.1 手机号码 用户填写的短信验证码 密码（未加密）
    params_dict = request.json
    mobile = params_dict.get("mobile")
    smscode = params_dict.get("smscode")
    password = params_dict.get("password")

    #2.1 非空判断
    if not all([mobile, smscode, password]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")
    # 2.2手机号码格式判断
    if not re.match('^1[356789][0-9]{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机格式错误")

    # 3.1 根据手机号码拼接SMS_13570882306这个key去redis获取真实短信验证码
    try:
        real_sms_code = redis_store.get("SMS_%s" % mobile)
        # 不想多次校验同一个短信验证码， 当取出真实值的时候iba他从数据库删除
        if real_sms_code:
            redis_store.delete("SMS_%s" % mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.NODATA, errmsg="获取短信验证码数据库异常")
    if not real_sms_code:
        # 没有值表示短信验证码过期了
        return jsonify(errno=RET.NODATA, errmsg="短信验证码过期")

    # 3.2 对比用户添加的短信验证码和真实的短信验证码对比
    if smscode !=real_sms_code:
        return jsonify(errno=RET.PARAMERR, errmsg="短信验证码填写错误")
    # 3.3 一致：根据User模型创建用户对象，保存到数据库
    # 创建用户对象  给对应属性赋值
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    # TODO 密码加密：需要将密码加密后赋值给password_hash
    # user.make_password_hash(password
    # 调用重写的setter方法
    user.password = password

    # 记录用户的最后一次登陆时间
    user.last_login = datetime.now()

    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存用户对象到数据库异常")

    # 3.4 一般而言：用户注册成功的话，第一次到会给用户自动登陆
    session["user_id"] = user.id
    session["mobile"] = user.mobile
    session["nick_name"]= user.nick_name

    # 4.返回值处理
    return jsonify(errno=RET.OK, errmsg="注册成功")



# POST:127.o.0.1:5000/passport/image_code
@passport_bp.route('/image_code')
def get_imagecode():
    """获取图片验证码图片"""
    # 1.获取参数
    # 1.1获取前端传上来的随机UUID编码， imageCodeId
    imageCodeId = request.args.get("imageCodeId")
    # 2.校验参数
    # 2.2 UUID编码 是否为空
    if not imageCodeId:
        abort(404)
    # 3.逻辑处理
    # 3.1 生成验证码图片对象， 验证码的真实值
    name, text, image = captcha.generate_captcha()
    # 3.2 将图片验证码真实值使用编码存储到redis
    # eg: imagecode_uuid:sadj
    try:
        redis_store.set("imagecode_%s" % imageCodeId, text, ex=constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        abort(500)

        # current_app.logger.error(e)
        # 4.返回值处理
        # 4.1 将图片对象返回给前端展示
    # 创建响应对象
    response = make_response(image)
    # 设置响应对象的响应头中返回值类型
    response.headers["Content-Type"] = "image/jpeg"
    return response


# POST:127.o.0.1:5000/passport/sms_code
@passport_bp.route('/sms_code',methods=["POST","GET"])
def send_sms():
    """点击发送短信验证码接口"""

    """
    1.获取参数
        1.1  手机号码 用户填写的验证码值 UUID随机值编号
    2.校验参数
        2.1 手机号码 用户填写的验证码值 UUID随机值编号判空校验
        2.2 手机号码格式是否正确
    3.逻辑处理
        3.1 根据image_code_id编号去redis中获取验证码的真实值
        3.1.1 real_image_code 验证码的真实值有值： 删除Redis中的存储的值 防止多次利用real_image_code来验证
        3.1.2 没有值： 代表redis中验证码值过期了 --> 细节： 调用前端的再次生成一张图片

        3.2 比较用户填写的image_code和后端真实的real_image_code进行对比
        成功：发送短信验证码
        失败：验证码填写错误

        3.3.0 根据手机号码去查询手机号码是否注册过        3.3.1 生成一个6位的随机短信内容

        3.4 发送短信验证码成功
        3.4.1 存储短信验证码到redis

    4.返回值处理 告知前端发送短信验证成功请注意查收

    """
    # 1.1  手机号码用户填写的验证码值　uuid随机值编号
    # request.json  直接将前端上传的json字符串转成python对象（dict or list)
    # param_dict = json.loads(request.data)
    param_dict = request.json
    mobile = param_dict.get("mobile")
    image_code = param_dict.get("image_code")
    image_code_id = param_dict.get("image_code_id")

    # 2.1　手机号码　用户填写的验证码值　uuid随机值编号判空校验
    if not all([mobile, image_code, image_code_id]):
        # 返回错误的json字符串(errno:4013,errmsg:"参数不足"
        return jsonify(errno = RET.PARAMERR, errmsg = "参数不足")

    # 2.2 手机号码格式是否正确
    if not re.match('1[346789][0-9]{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机格式错误")
    try:
        # 3.1 根据image_code_id编号去redis中获取验证码的真实值
        # 注意一定要在redis 创建的时候去设置这个decode_responses=True属性
        real_image_code = redis_store.get("imagecode_%s" % image_code_id)

        # 3.1.1 real_image_code 验证码的真实值有值： 删除Redis中的存储的值 防止多次利用real_image_code来验证
        if real_image_code:
            redis_store.delete(real_image_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询验证码真实值异常")

    # 3.1.2 没有值: 代表redis中验证码过期了－－－>细节：调用前段的再生成一张图片
    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg="验证码过期")

    # 3.2 比较用户填写的imgage_code和后端真实的real_image_code进行对比
    if image_code.lower() != real_image_code.lower():
        # 失败：验证码填写错误
        return jsonify(errno=RET.DBERR, errmsg="验证码填写错误")

    try:
        # 3.3.0 根据手机号码去查询手机号码是否注册过
        user = User.query.filter_by(mobile=mobile).first()
        if user:
            # 有值的话 表示该手机号码注册过了
            return jsonify(errno=RET.DATAEXIST,errmsg="手机号码注册过")
    except Exception as e:
        # 记录日志
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")

    # 3.3 调用云通讯的SDK发送短信验证码
    # 3.3.1 生成一个６位的随机短信内容
    sms_code = random.randint(0, 999999)
    sms_code = "%06d" % sms_code

    # 下面绕开短信验证， (将后端生成的注册码打印一下）
    current_app.logger.debug(sms_code)

    # result = CCP().send_template_sms(mobile, [sms_code, constants.IMAGE_CODE_REDIS_EXPIRES/60],1)
    #
    # if result !=0:
    #     # 发送短信验证码成功
    #     return jsonify(errno=RET.THIRDERR, errmsg="发送短信验证码失败")

    # 3.4 发送短信验证码成功
    # 3.4.1 存储短信验证码到redis
    try:
        redis_store.set("SMS_%s" %mobile, sms_code, ex=constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="保存短信验证码到数据库异常")

    # 4. 返回值处理　告知前段发送短信验证码成功请注意查收
    return jsonify(errno=RET.OK, errmsg="发送短信验证成功")




